#ifndef __FIBER_MUTEX_H_
#define __FIBER_MUTEX_H_

// 包含系统头文件和工具类
#include <pthread.h>         // 线程库（提供pthread_mutex_t等同步原语）
#include <semaphore.h>       // 信号量系统接口
#include "noncopyable.h"     // 不可复制基类（禁止拷贝构造和赋值）
#include "utils.h"           // 工具函数（如CondPanic断言）

namespace fiber 
{

// 信号量类：用于线程间的同步（基于sem_t实现）
// 继承Nonecopyable：禁止信号量对象被复制（信号量不可复制）
class Semaphore : Nonecopyable {
public:
    /**
     * @brief 构造函数：初始化信号量
     * @param count 信号量初始计数（默认为0）
     * 信号量计数>0时，wait()不阻塞；=0时，wait()阻塞直到被notify()唤醒
     */
    Semaphore(uint32_t count = 0) {
        // 初始化信号量，count为初始计数
        int ret = sem_init(&m_semaphore, 0, count); 
        CondPanic(ret == 0, "sem_init failed"); // 用工具函数检查初始化结果
    }

    /**
     * @brief 析构函数：销毁信号量
     */
    ~Semaphore() {
        // 销毁信号量
        int ret = sem_destroy(&m_semaphore);
        CondPanic(ret == 0, "sem_destroy failed");
    }

    /**
     * @brief 等待信号量（P操作）
     * 若计数>0，计数减1并返回；若=0，阻塞当前线程直到被notify()唤醒
     */
    void wait() {
        // 等待信号量（P操作：计数-1，若计数为0则阻塞）
        int ret = sem_wait(&m_semaphore);
        CondPanic(ret == 0, "sem_wait failed");
    }

    /**
     * @brief 发送信号（V操作）
     * 计数加1，若有线程阻塞在wait()，唤醒其中一个
     */
    void notify() {
        // 发送信号（V操作：计数+1，唤醒阻塞的线程）
        int ret = sem_post(&m_semaphore);
        CondPanic(ret == 0, "sem_post failed");
    }

private:
    sem_t m_semaphore;  // 系统信号量对象（封装POSIX信号量）
};

// 局部锁模板类：基于RAII机制管理普通互斥锁的自动加锁/解锁
// 模板参数T：互斥锁类型（如Mutex）
template <class T>
struct ScopedLockImpl {
public:
    /**
     * @brief 构造函数：获取锁并标记上锁状态
     * @param mutex 互斥锁对象引用（通过引用避免拷贝）
     * 构造时自动调用mutex.lock()加锁，确保资源进入作用域时被锁定
     */
    ScopedLockImpl(T& mutex) 
    : m_mutex(mutex) {
        m_mutex.lock();       // 加锁
        m_isLocked = true;    // 标记已上锁
    }

    /**
     * @brief 手动加锁（若未上锁）
     */
    void lock() {
        if (!m_isLocked) {  // 避免重复加锁
            m_mutex.lock();
            m_isLocked = true;
        }
    }

    /**
     * @brief 手动解锁（若已上锁）
     */
    void unlock() {
        if (m_isLocked) {   // 避免重复解锁
            m_mutex.unlock();
            m_isLocked = false;
        }
    }

    /**
     * @brief 析构函数：自动解锁
     * 离开作用域时自动调用unlock()，确保锁被释放（防止死锁）
     */
    ~ScopedLockImpl() {
        unlock();
    }

private:
    T& m_mutex;         // 互斥锁对象引用（关联外部锁）
    bool m_isLocked;    // 标记是否已上锁（避免重复操作）
};

// 局部读锁模板类：基于RAII机制管理读写锁的读锁
// 模板参数T：读写锁类型（如RWMutex）
template <class T>
struct ReadScopedLockImpl {
public:
    /**
     * @brief 构造函数：获取读锁并标记状态
     * @param mutex 读写锁对象引用
     * 构造时自动调用mutex.rdlock()加读锁（读锁可共享）
     */
    ReadScopedLockImpl(T& mutex) 
    : m_rmutex(mutex) {
        m_rmutex.rdlock();  // 加读锁
        m_isLocked = true;
    }

    /**
     * @brief 析构函数：自动释放读锁
     */
    ~ReadScopedLockImpl() { unlock(); }

    /**
     * @brief 手动加读锁（若未上锁）
     */
    void lock() {
        if (!m_isLocked) {
            m_rmutex.rdlock();
            m_isLocked = true;
        }
    }

    /**
     * @brief 手动释放读锁（若已上锁）
     */
    void unlock() {
        if (m_isLocked) {
            m_rmutex.unlock();
            m_isLocked = false;
        }
    }

private:
    T& m_rmutex;        // 读锁对象引用
    bool m_isLocked;    // 标记是否已上读锁
};

// 局部写锁模板类：基于RAII机制管理读写锁的写锁
// 模板参数T：读写锁类型（如RWMutex）
template <class T>
struct WriteScopedLockImpl {
public:
    /**
     * @brief 构造函数：获取写锁并标记状态
     * @param mutex 读写锁对象引用
     * 构造时自动调用mutex.wrlock()加写锁（写锁排他）
     */
    WriteScopedLockImpl(T &mutex) 
    : m_wmutex(mutex) {
        m_wmutex.wrlock();  // 加写锁
        m_isLocked = true;
    }

    /**
     * @brief 析构函数：自动释放写锁
     */
    ~WriteScopedLockImpl() { unlock(); }

    /**
     * @brief 手动加写锁（若未上锁）
     */
    void lock() {
        if (!m_isLocked) {
            m_wmutex.wrlock();
            m_isLocked = true;
        }
    }

    /**
     * @brief 手动释放写锁（若已上锁）
     */
    void unlock() {
        if (m_isLocked) {
            m_wmutex.unlock();
            m_isLocked = false;
        }
    }

private:
    T& m_wmutex;        // 读写锁对象引用
    bool m_isLocked;   // 标记是否已上写锁
};

// 互斥锁类：封装pthread_mutex_t（排他锁，同一时间仅一个线程持有）
// 继承Nonecopyable：禁止互斥锁被复制（互斥锁不可复制）
class Mutex : Nonecopyable {
public:
    // 定义局部锁类型：使用ScopedLockImpl管理当前Mutex的自动加锁/解锁
    using Lock = ScopedLockImpl<Mutex>;

    /**
     * @brief 构造函数：初始化互斥锁
     * 调用pthread_mutex_init初始化，并用CondPanic检查是否成功（失败则断言）
     */
    Mutex() { 
        // 若pthread_mutex_init返回非0（失败），CondPanic会输出错误并触发断言
        CondPanic(0 == pthread_mutex_init(&m_mutex, nullptr), "lock init success"); 
    }

    /**
     * @brief 加锁操作
     * 调用pthread_mutex_lock，失败则触发断言
     */
    void lock() { 
        CondPanic(0 == pthread_mutex_lock(&m_mutex), "lock error"); 
    }

    /**
     * @brief 解锁操作
     * 调用pthread_mutex_unlock，失败则触发断言
     */
    void unlock() { 
        CondPanic(0 == pthread_mutex_unlock(&m_mutex), "unlock error"); 
    }

    /**
     * @brief 析构函数：销毁互斥锁
     * 调用pthread_mutex_destroy，失败则触发断言
     */
    ~Mutex() { 
        CondPanic(0 == pthread_mutex_destroy(&m_mutex), "destroy lock error"); 
    }

private:
    pthread_mutex_t m_mutex;  // 系统互斥锁对象（封装POSIX互斥锁）
};

// 读写锁类：封装pthread_rwlock_t（读共享、写排他，适合读多写少场景）
// 继承Nonecopyable：禁止读写锁被复制
class RWMutex : Nonecopyable {
public:
    // 定义局部读锁类型：使用ReadScopedLockImpl管理读锁
    using ReadLock = ReadScopedLockImpl<RWMutex>;
    // 定义局部写锁类型：使用WriteScopedLockImpl管理写锁
    using WriteLock = WriteScopedLockImpl<RWMutex>;

    /**
     * @brief 构造函数：初始化读写锁
     * 调用pthread_rwlock_init初始化
     */
    RWMutex() { 
        pthread_rwlock_init(&m_rwmutex, nullptr); 
    }

    /**
     * @brief 析构函数：销毁读写锁
     * 调用pthread_rwlock_destroy
     */
    ~RWMutex() { 
        pthread_rwlock_destroy(&m_rwmutex); 
    }

    /**
     * @brief 获取读锁（共享锁）
     * 多个线程可同时持有读锁，与写锁互斥
     */
    void rdlock() { 
        pthread_rwlock_rdlock(&m_rwmutex); 
    }

    /**
     * @brief 获取写锁（排他锁）
     * 仅一个线程可持有写锁，与读锁、其他写锁互斥
     */
    void wrlock() { 
        pthread_rwlock_wrlock(&m_rwmutex); 
    }

    /**
     * @brief 释放锁（读锁或写锁）
     * 无论当前持有读锁还是写锁，均通过此方法释放
     */
    void unlock() { 
        pthread_rwlock_unlock(&m_rwmutex); 
    }

private:
    pthread_rwlock_t m_rwmutex;  // 系统读写锁对象（封装POSIX读写锁）
};

}  // namespace fiber

#endif  // __FIBER_MUTEX_H_